#pragma once

#include "RecordMockedFunction.h"

#define REGISTER_FREE_FUNCTION(NumArgs, ReturnValueType, ...) \
	void RegisterFunction(ReturnValueType (*function)(__VA_ARGS__)) \
	{ \
		MOCKITNOW_STATIC_ASSERT(IsConst<ReturnValueType>::Value == false || IsValue<ReturnValueType>::Value == false, CannotMockFunctionsReturningConstByValue); \
		const size_t mockFunctionAddress = GetFunctionAddress(function); \
		const size_t recordFunctionAddress = GetFunctionAddress((ReturnValueType (*)(__VA_ARGS__))&FreeFunctionRecorder##NumArgs<ReturnValueType, __VA_ARGS__>::RecordMockedFunction); \
		const size_t replayFunctionAddress = GetFunctionAddress((ReturnValueType (*)(__VA_ARGS__))&FreeFunctionReplayer##NumArgs<ReturnValueType, __VA_ARGS__>::ReplayMockedFunction); \
		RegisterFunction(mockFunctionAddress, recordFunctionAddress, replayFunctionAddress, IsVoid<ReturnValueType>::Value == false); \
	}

#define REGISTER_MEMBER_FUNCTION__(NumArgs, FunctionQualifier, ReturnValueType, ...) \
	void RegisterFunction(ReturnValueType (T::*function)(__VA_ARGS__) FunctionQualifier) \
	{ \
		MOCKITNOW_STATIC_ASSERT(IsConst<ReturnValueType>::Value == false || IsValue<ReturnValueType>::Value == false, CannotMockFunctionsReturningConstByValue); \
		const size_t mockFunctionAddress = FixVirtualFunction<T>(GetFunctionAddress(function)); \
		const size_t recordFunctionAddress = GetFunctionAddress((ReturnValueType (MemberFunctionRecorder##NumArgs<ReturnValueType, __VA_ARGS__>::*)(__VA_ARGS__))&MemberFunctionRecorder##NumArgs<ReturnValueType, __VA_ARGS__>::RecordMockedFunction); \
		const size_t replayFunctionAddress = GetFunctionAddress((ReturnValueType (MemberFunctionReplayer##NumArgs<ReturnValueType, __VA_ARGS__>::*)(__VA_ARGS__))&MemberFunctionReplayer##NumArgs<ReturnValueType, __VA_ARGS__>::ReplayMockedFunction); \
		RegisterFunction(mockFunctionAddress, recordFunctionAddress, replayFunctionAddress, IsVoid<ReturnValueType>::Value == false); \
	} \

#define REGISTER_MEMBER_FUNCTION(NumArgs, ReturnValueType, ...) REGISTER_MEMBER_FUNCTION__(NumArgs, , ReturnValueType, __VA_ARGS__)
#define REGISTER_CONST_MEMBER_FUNCTION(NumArgs, ReturnValueType, ...) REGISTER_MEMBER_FUNCTION__(NumArgs, const, ReturnValueType, __VA_ARGS__)
